// 2.重载运算符和重载函数
/**
 * 1. 重载函数
 *      同名函数，参数个数、类型、顺序不同，不能根据返回值类型重载
 *
 * 2. 运算符重载
 *      语法:(+示例)
 *        return_type operator+ (const class_name &obj); // 两个自定义类相加，成员函数中自己可以通过this拿
 *        return_type operator+ (const class_name &obj1, const class_name &obj2); // 非成员函数（如友元函数），无this，那就传两个参数       注意：非成员函数有时候是必要的，比如自定义类与其他类型相加，要考虑参数的顺序
 *
 * 3. 哪些运算符可以重载，哪些运算符不可以重载
 *     #31可重载运算符：
 *          双目算数运算符    + - * / %
 *          关系运算符        == != < > <= >=
 *          逻辑运算符        || && !
 *          单目运算符        +（正） -（负） *（指针） &（取地址）
 *          自增自减运算符    ++ --
 *          位运算符          | & ~ ^ << >>
 *          赋值运算符        = += -= *= /= %= &= |= ^= <<= >>=
 *          空间申请与释放    new delete new[] delete[]
 *          其他运算符        ()（函数调用） ->  []（下标）
 *          输入/输出运算符   >>（流提取运算符） <<（流插入运算符）
 *
 *       不可重载运算符：
 *          .         成员访问运算符
 *          .*  ->*   成员指针访问运算符
 *          ::        域运算符
 *          sizeof    长度运算符
 *          ?:        条件运算符
 *          #         预处理运算符
 *
 *        注意:
 *          1. 逻辑运算符!重载，成员函数无参对应 !obj ,注意不是按那个左右顺序。友元函数，一参。单目运算符跟它一样，前置自增自减，位运算符~
 *          2. 自增、自减运算符 通过是否有运算符函数参数（int）来区分前置后置
 *                如:
 *                  成员函数
 *                     return_type operator++ (){} // 前置
 *                     return_type operator++ (int){} // 后置
 *                  友元函数
 *                     friend return_type operator++ (class_name &obj){} // 前置
 *                     friend return_type operator++ (class_name &obj,int){} // 后置,int必须作为第二个参数
 *          3. 部分重载运算符( 赋值运算符= [] () ->)函数 只能是成员函数
 *          4. 空间申请和释放 new、delete、new[]、delete[] 语法注意
 *              void *operator new(size_t size);
 *              friend void *operator new[](size_t size);
 *              void operator delete(void *pdead);
 *              friend void operator delete[](void *pdead);
 *              ... new/new[]、delete/delete[]语法类似 ，我就列四个区分出 成员函数和友元函数的区别
 *
 *          5. 成员访问运算符->重载有点特殊，重载后使用;
 *               成员函数 return_type operator->(){}
 *               obj->func();// 被解释为 (obj.operator->())->func(); 我的理解是不好拿->后面跟的成员变量标识符 或者 也有办法拿只是我不知道.
 *          x. 流插入运算符和流提取运算符，考虑到使用时顺序问题，流在左边，变量在右边，最好用友元函数定义, 避免出现  xxx << cout ;
 *              friend std::ostream operator<<(std::ostream &os,xxx);
 *          6. 流提取运算符>>和流插入运算符<<
 *                感觉就是 operator>> 和operator<< 的重载 ，<< >>还是位运算符。注意左右顺序。最好用友元函数
 *
 * 扩展:（#xx1 末尾补1）
 *  1. #111隐式类型转换方法重载
 *      语法：operator type(){}
 *        注意** 不需要返回类型
 *
 * 疑问:
 *  1. 如何模拟js || && 运算符 (template + auto c++14支持，c++11如何实现)
 *  2. 重载运算符函数优先匹配成员函数？不管友元函数在它上面声明还是在它下面声明，在类内定义还是在内外定义.
 *  3. 类Test中使用new A;会调用test友元 new重载运算符函数，不会调成员函数，怎么避免它调重载运算符函数，只能使用成员函数版本吗？
 *  4. 隐式类型转换函数必须是一个nostatic member function.那友元函数命中的是nostatic 还是 只是 命中非成员函数？
 */

#include <iostream>
#include <cmath>

#define __mark 31

/**
 * #31 可重载运算符
 */
#if __mark == 31
class A
{
public:
  int a;
  A() : a(0) {}
  A(int _a) : a(_a) {}
};
class Test
{
public:
  // new Test 需要默认的构造函数
  int b;
  Test() : a(0) {}
  Test(int _a) : a(_a) {}
  ~Test() {}
  Test(const Test &) {}

private:
  int a;

public:
  /**
   * 1. 双目算数运算符 + - * / %
   */

  // 必须要 public修饰
  int operator+(int _i)
  {
    std::cout << "Test + _i" << std::endl;
    return this->a + _i;
  }

  int operator-(int _i)
  {
    std::cout << "Test - _i" << std::endl;
    return this->a - _i;
  }

  int operator*(int _i)
  {
    std::cout << "Test * _i" << std::endl;
    return this->a * _i;
  }

  int operator/(int _i)
  {
    // /注意 _i不能为0
    std::cout << "Test / _i" << std::endl;
    return this->a / _i;
  }
  int operator%(int _i)
  {
    // /注意 _i不能为0
    std::cout << "Test % _i" << std::endl;
    return this->a % _i;
  }

  /**
   * 2. 关系运算符 == != < > <= >=
   */
  bool operator==(int _i)
  {
    std::cout << "Test == _i" << std::endl;
    return a == _i;
  }
  bool operator!=(int _i)
  {
    std::cout << "Test != _i" << std::endl;
    return a != _i;
  }
  bool operator<(int _i)
  {
    std::cout << "Test < _i" << std::endl;
    return a < _i;
  }

  bool operator>(int _i)
  {
    std::cout << "Test > _i" << std::endl;
    return a > _i;
  }

  bool operator<=(int _i)
  {
    std::cout << "Test <= _i" << std::endl;
    return a <= _i;
  }

  bool operator>=(int _i)
  {
    std::cout << "Test >= _i" << std::endl;
    return a >= _i;
  }

  /**
   * 3. 逻辑运算符 || && !
   */
  // 成员函数无法写。。。
  // template<class T>
  // T operator||(int _i)
  // {
  //   // 改下，模拟js（输出第一个真值或最后一个值）
  //   std::cout << "Test || _i" << std::endl;
  //   return a >= _i;
  // }
  // int operator&&(int _i)
  // {
  //   // 改下，模拟js（输出遇到的第一个假值或最后一个真值）
  //   std::cout << "Test || _i" << std::endl;
  //   return a >= _i;
  // }

  // 优先匹配成员函数
  bool operator!()
  {
    std::cout << "Test !" << std::endl;
    return !a;
  }
  // friend bool operator!(const Test &obj);

  /**
   * 4. 单目运算符 + - * &
   */
  int operator+()
  {
    std::cout << "+ Test" << std::endl;
    return a;
  }

  int operator-()
  {
    std::cout << "- Test" << std::endl;
    return -a;
  }

  int operator*()
  {
    std::cout << "* Test" << std::endl;
    return a;
  }

  int *operator&()
  {
    std::cout << "& Test" << std::endl;
    return &this->a;
  }
  /**
   * 5. 自增自减运算符    ++ --
   */
  /**
  int operator++()
  {
    // 前置 先计算后输出
    std::cout << "++Test" << std::endl;
    a += 1;
    return this->a;
  }
  int operator++(int)
  {
    // 后置 先输出后计算
    std::cout << "Test++" << std::endl;
    int t = this->a;
    a += 1;
    return t;
  }
  int operator--()
  {
    // 前置 先计算后输出
    std::cout << "--Test" << std::endl;
    a -= 1;
    return this->a;
  }
  int operator--(int)
  {
    // 后置 先输出后计算
    std::cout << "Test--" << std::endl;
    int t = this->a;
    a -= 1;
    return t;
  }
  */

  /**
   * 6. 位运算符 | & ~ ^ << >>
   */
  int operator|(int _i)
  {
    std::cout << "Test | _i" << std::endl;
    return a | _i;
  }
  int operator&(int _i)
  {
    std::cout << "Test & _i" << std::endl;
    return a & _i;
  }
  int operator^(int _i)
  {
    std::cout << "Test ^ _i" << std::endl;
    return a ^ _i;
  }
  int operator<<(int _i)
  {
    std::cout << "Test << _i" << std::endl;
    return a << _i;
  }
  int operator>>(int _i)
  {
    std::cout << "Test >> _i" << std::endl;
    return a >> _i;
  }

  int operator~()
  {
    std::cout << "~Test" << std::endl;
    return ~a;
  }

  /**
   * 7.赋值运算符 = += -= *= /= &= |= ^= <<= >>=
   */
  void operator=(int _i)
  {
    std::cout << "Test = _i" << std::endl;
    a = _i;
  }

  void operator+=(int _i)
  {
    std::cout << "Test += _i" << std::endl;
    a += _i;
  }

  void operator-=(int _i)
  {
    std::cout << "Test -= _i" << std::endl;
    a -= _i;
  }

  void operator*=(int _i)
  {
    std::cout << "Test *= _i" << std::endl;
    a *= _i;
  }

  void operator/=(int _i)
  {
    std::cout << "Test /= _i" << std::endl;
    a /= _i;
  }

  void operator%=(int _i)
  {
    std::cout << "Test %= _i" << std::endl;
    a %= _i;
  }

  void operator&=(int _i)
  {
    std::cout << "Test &= _i" << std::endl;
    a &= _i;
  }

  void operator|=(int _i)
  {
    std::cout << "Test |= _i" << std::endl;
    a |= _i;
  }

  void operator^=(int _i)
  {
    std::cout << "Test ^= _i" << std::endl;
    a ^= _i;
  }

  void operator<<=(int _i)
  {
    std::cout << "Test <<= _i" << std::endl;
    a <<= _i;
  }

  void operator>>=(int _i)
  {
    std::cout << "Test >>= _i" << std::endl;
    a >>= _i;
  }

  /**
   * 8.空间申请和释放 new delete new[] delete[]
   */
  // void *operator new(size_t size)
  // {
  //   std::cout << "Test::operator new" << std::endl;
  //   Test *pt = (Test *)malloc(size);
  //   return pt;
  // }
  // void operator delete(void *pdead, size_t size)
  // {
  //   std::cout << "Test::operator delete" << std::endl;
  //   free(pdead);
  // }

  // void *operator new[](size_t size)
  // {
  //   std::cout << "Test::operator new[]" << std::endl;
  //   Test *pt = (Test *)malloc(size);
  //   return pt;
  // }

  // void operator delete[](void *pdead, size_t size)
  // {
  //   std::cout << "Test::operator delete[]" << std::endl;
  //   free(pdead);
  // }
  /**
   * 9. 其他运算符 () 函数调用 [] 下标  -> 成员访问运算符
   *
   */
  int operator()(int _i)
  {
    std::cout << "Test(int)" << std::endl;
    return a + _i;
  }

  int operator[](int _i)
  {
    // 参数必须
    // 下标操作符[]通常用于访问数组元素，重载该运算符用于增强操作C++数组的功能

    std::cout << "Test[int]" << std::endl;
    return a + _i;
  }

  A *operator->()
  {
    // 参数必须
    std::cout << "Test->" << std::endl;

    A *pa = new A(22);
    return pa;
  }
  /**
   * 10. 流提取运算符>> 流插入运算符<<
   *
   */
  std::ostream &operator<<(std::ostream &os)
  {
    os << "Test << os";
    return os;
  }

  std::istream &operator>>(std::istream &is)
  {
    std::cout << "Test >> is" << std::endl;
    is >> b;
    return is;
  }

private:
  // 友元函数可以用private修饰
  friend int operator+(int _i, const Test &obj)
  {
    std::cout << "_i + Test" << std::endl;
    return _i + obj.a;
  }
  friend int operator-(int _i, const Test &obj)
  {
    std::cout << "_i - Test" << std::endl;
    return _i - obj.a;
  }
  friend int operator*(int _i, const Test &obj)
  {
    std::cout << "_i * Test" << std::endl;
    return _i * obj.a;
  }
  friend int operator/(int _i, const Test &obj)
  {
    // 注意处理 obj.a 不为0
    std::cout << "_i / Test" << std::endl;
    return _i / obj.a;
  }
  friend int operator%(int _i, const Test &obj)
  {
    // 注意处理 obj.a 不为0
    std::cout << "_i % Test" << std::endl;
    return _i % obj.a;
  }

  /**
   * 2.关系运算符
   */
  friend bool operator==(int _i, const Test &obj)
  {
    std::cout << "_i == Test" << std::endl;
    return _i == obj.a;
  }

  friend bool operator!=(int _i, const Test &obj)
  {
    std::cout << "_i != Test" << std::endl;
    return _i != obj.a;
  }
  friend bool operator<(int _i, const Test &obj)
  {
    std::cout << "_i < Test" << std::endl;
    return _i < obj.a;
  }
  friend bool operator>(int _i, const Test &obj)
  {
    std::cout << "_i > Test" << std::endl;
    return _i > obj.a;
  }
  friend bool operator<=(int _i, const Test &obj)
  {
    std::cout << "_i <= Test" << std::endl;
    return _i <= obj.a;
  }
  friend bool operator>=(int _i, const Test &obj)
  {
    std::cout << "_i >= Test" << std::endl;
    return _i >= obj.a;
  }
  /**
   * 3. 逻辑运算符
   */
  // c++14 return auto + template是可以使用的
  // template <class T>
  // friend auto operator||(T _i, const Test &obj)
  // {
  //   // 改下，模拟js（输出第一个真值或最后一个值）
  //   std::cout << "_i || Test" << std::endl;
  //   if (_i)
  //   {
  //     return _i;
  //   }
  //   else
  //   {
  //     return obj.a;
  //   }
  // }
  // template <class T>
  // friend auto operator&&(T _i, const Test &obj)
  // {
  //   // 改下，模拟js（输出遇到的第一个假值或最后一个真值）
  //   std::cout << "_i && Test" << std::endl;
  //   if (!_i)
  //   {
  //     return _i;
  //   }
  //   else
  //   {
  //     return obj.a;
  //   }
  // }

  friend bool operator!(const Test &obj)
  {
    std::cout << "! Test" << std::endl;
    return !obj.a;
  }

  /**
   * 5. 自增自减运算符 ++ --
   */
  friend int operator++(Test &obj)
  {
    // 前置
    std::cout << "++Test" << std::endl;
    return ++obj.a;
  }
  friend int operator++(Test &obj, int)
  {
    // 前置
    std::cout << "Test++" << std::endl;
    return obj.a++;
  }
  friend int operator--(Test &obj)
  {
    // 前置
    std::cout << "--Test" << std::endl;
    return --obj.a;
  }
  friend int operator--(Test &obj, int)
  {
    // 前置
    std::cout << "Test--" << std::endl;
    return obj.a--;
  }
  /**
   * 6. 位运算符 | & ~ ^ << >>
   */
  friend bool operator|(int _i, const Test &obj)
  {
    std::cout << "_i | Test" << std::endl;
    return _i | obj.a;
  }
  friend bool operator&(int _i, const Test &obj)
  {
    std::cout << "_i & Test" << std::endl;
    return _i & obj.a;
  }
  friend bool operator^(int _i, const Test &obj)
  {
    std::cout << "_i ^ Test" << std::endl;
    return _i ^ obj.a;
  }

  // friend bool operator<<(const Test &obj,int _i )
  // {
  //   std::cout << "Test << _i" << std::endl;
  //   return _i << obj.a;
  // }
  // friend bool operator>>(const Test &obj,int _i)
  // {
  //   std::cout << "Test >> _i" << std::endl;
  //   return _i >> obj.a;
  // }

  // friend bool operator~(const Test &obj)
  // {
  //   std::cout << "~Test" << std::endl;
  //   return ~obj.a;
  // }

  /**
   * 7.赋值运算符 = += -= *= /= &= |= ^= <<= >>=
   */
  //  friend void operator=(int _i,Test &obj){
  //    std::cout << "_i = Test" << std::endl;
  //  }

  friend void operator+=(int _i, Test &obj)
  {
    std::cout << "_i += Test" << std::endl;
    _i += obj.a;
  }
  friend void operator-=(int _i, Test &obj)
  {
    std::cout << "_i -= Test" << std::endl;
    _i -= obj.a;
  }
  friend void operator*=(int _i, Test &obj)
  {
    std::cout << "_i *= Test" << std::endl;
    _i *= obj.a;
  }
  friend void operator/=(int _i, Test &obj)
  {
    std::cout << "_i /= Test" << std::endl;
    _i /= obj.a;
  }
  friend void operator%=(int _i, Test &obj)
  {
    std::cout << "_i %= Test" << std::endl;
    _i %= obj.a;
  }
  friend void operator&=(int _i, Test &obj)
  {
    std::cout << "_i &= Test" << std::endl;
    _i &= obj.a;
  }
  friend void operator|=(int _i, Test &obj)
  {
    std::cout << "_i |= Test" << std::endl;
    _i |= obj.a;
  }
  friend void operator^=(int _i, Test &obj)
  {
    std::cout << "_i ^= Test" << std::endl;
    _i ^= obj.a;
  }
  friend void operator<<=(int _i, Test &obj)
  {
    std::cout << "_i <<= Test" << std::endl;
    _i <<= obj.a;
  }
  friend void operator>>=(int _i, Test &obj)
  {
    std::cout << "_i >>= Test" << std::endl;
    _i >>= obj.a;
  }

  /**
   * 8. 空间申请和释放 new delete new[] delete[]
   */
  //  size_t size, Test &obj
  friend void *operator new(size_t size)
  {
    //第一个参数必须是size_t size
    std::cout << "friend operator new" << std::endl;
    Test *pt = (Test *)malloc(size);
    return pt;
  }
  // void *pdead, size_t size, Test &obj
  friend void operator delete(void *pdead)
  {
    // 第一个参数必须是 void *pdead
    std::cout << "friend opeartor delete " << std::endl;
    free(pdead);
  }
  // size_t size, Test &obj
  friend void *operator new[](size_t size)
  {
    std::cout << "friend operator new[]" << std::endl;
    Test *pt = (Test *)malloc(size);
    return pt;
  }

  friend void operator delete[](void *pdead)
  {
    std::cout << "friend operator delete[]" << std::endl;
    free(pdead);
  }
  /**
   * 9. 其他运算符 () 函数调用 -> 成员访问运算符 [] 下标
   */
  //  operator()必须是成员函数
  //  friend int operator() (){

  //  }
  // operator->必须是成员函数
  // friend Test *operator->()
  // {
  // }
  // operator[] 必须是成员函数
  // friend operator[](int _i){

  // }

  /**
   * 10. 流提取运算符>> 流插入运算符<<
   *
   */
  //  注意：要返回引用 传入的也是引用
  friend std::ostream &operator<<(std::ostream &os, Test &obj)
  {
    os << "Test operator <<" << obj.a;
    return os;
  }

  friend std::istream &operator>>(std::istream &is, Test &obj)
  {
    std::cout << "Test operator >>" << std::endl;
    is >> obj.b;
    return is;
  }
};
// bool operator!(const Test &obj)
// {
//   std::cout << "! Test" << std::endl;
//   return !obj.a;
// }

// int operator+(int _i, const Test &obj)
// {
//   std::cout << "_i + Test" << std::endl;
//   return obj.a + _i;
// }

int main(void)
{
  Test t1(-1);
  printf("\n------------双目算数运算符----------------\n");
  std::cout << (2 + t1) << std::endl;
  std::cout << (t1 + 3) << std::endl;
  // std::cout << (1 / 0) << std::endl;
  // std::cout << (1 % 0) << std::endl;
  std::cout << (2 - t1) << std::endl;
  std::cout << (t1 - 3) << std::endl;

  std::cout << (2 * t1) << std::endl;
  std::cout << (t1 * 3) << std::endl;

  std::cout << (2 / t1) << std::endl;
  std::cout << (t1 / 3) << std::endl;

  std::cout << (2 % t1) << std::endl;
  std::cout << (t1 % 3) << std::endl;

  printf("\n------------关系运算符----------------\n");

  std::cout << (2 == t1) << std::endl;
  std::cout << (t1 == 3) << std::endl;

  std::cout << (2 != t1) << std::endl;
  std::cout << (t1 != 3) << std::endl;

  std::cout << (2 < t1) << std::endl;
  std::cout << (t1 < 3) << std::endl;

  std::cout << (2 > t1) << std::endl;
  std::cout << (t1 > 3) << std::endl;

  std::cout << (2 <= t1) << std::endl;
  std::cout << (t1 <= 3) << std::endl;

  std::cout << (2 >= t1) << std::endl;
  std::cout << (t1 >= 3) << std::endl;

  printf("\n------------逻辑运算符----------------\n");
  // std::cout << (2 && t1) << std::endl;
  // std::cout << (3 || t1) << std::endl;
  std::cout << (!t1) << std::endl;
  // std::cout << (t1!) << std::endl;

  printf("\n------------单目运算符----------------\n");
  std::cout << (+t1) << std::endl;
  std::cout << (-t1) << std::endl;
  std::cout << (*t1) << std::endl;
  std::cout << (&t1) << std::endl;
  printf("\n------------自增自减运算符----------------\n");
  std::cout << t1++ << std::endl;
  std::cout << --t1 << std::endl;
  std::cout << ++t1 << std::endl;
  std::cout << t1-- << std::endl;

  printf("\n------------位运算符----------------\n");
  std::cout << (t1 | 1) << std::endl;
  std::cout << (1 | t1) << std::endl;
  std::cout << (t1 & 1) << std::endl;
  std::cout << (1 & t1) << std::endl;
  std::cout << (t1 ^ 1) << std::endl;
  std::cout << (1 ^ t1) << std::endl;
  std::cout << (t1 << 1) << std::endl;
  std::cout << (t1 >> 1) << std::endl;
  std::cout << (~t1) << std::endl;
  printf("\n------------赋值运算符----------------\n");
  t1 = 0;
  t1 += 1;
  t1 -= 2;
  t1 *= 7;
  t1 /= 2;
  t1 %= 2;
  t1 |= 2;
  t1 ^= 2;
  t1 <<= 2;
  t1 >>= 2;

  int a = 1;
  a += t1;
  a -= t1;
  a *= t1;
  a /= t1;
  a %= t1;
  a |= t1;
  a ^= t1;
  a <<= t1;
  a >>= t1;
  printf("\n------------空间申请和释放----------------\n");
  Test *pa = new Test();
  // Test *pa = new Test(1);
  delete pa;
  // Test *arr = new Test[10];
  Test *arr = new Test[10]{(1), (2)};
  delete[] arr;
  printf("\n------------其他运算符----------------\n");
  std::cout << t1(2) << std::endl;
  std::cout << t1[3] << std::endl;
  std::cout << t1->a << std::endl; // 等价于 (t1.operator->())->a
  printf("\n------------流提取运算符>> 流插入运算符<<----------------\n");
  std::cout << t1 << std::endl;
  std::cin >> t1;
  t1 << std::cout;
  t1 >> std::cin;

  printf("------------end----------------\n");
  return 0;
}
#elif __mark == 111
class Test
{
private:
  int a;

public:
  Test() : a(0) {}
  Test(int _a) : a(_a) {}
  operator char()
  {
    std::cout << "(char)Test" << std::endl;
    return (char)a;
  }
  operator long()
  {
    std::cout << "(long)Test" << std::endl;
    return (long)a;
  }

  //  'operator bool()' must be a nonstatic member function
  // friend operator bool()
  // {
  //   std::cout << "(bool)Test" << std::endl;
  //   return (bool)a;
  // }
};

int main(void)
{
  Test t1(65 + 32);
  char ch = t1;
  std::cout << ch << std::endl;
  std::cout << (long)t1 << std::endl;
  printf("--------------end-------------\n");
  return 0;
}
#endif
